{% extends "glgl_app/base.html" %}
<!--link type="text/css" rel="stylesheet" href="/static/css/force/style.css"-->
{% block title %}知识图谱2{% endblock %}
{% block extracss %}
    <link rel="stylesheet" href="/static/css/kn_other_map.min.css">
    <style type="text/css">
        circle.node {
          cursor: pointer;
          stroke: #000;
          stroke-width: .5px;
        }
        line.link {
          fill: none;
          stroke: #9ecae1;
          stroke-width: 1.5px;
        }
    </style>
{% endblock %}

{% block content %}
<div class="mainCol padding15px addcolor">
    <div class="setborder"><!--是setborder让它有了阴影-->
        <div id="mapRow" class="kl_str"></div><!--在loadmap函数里面选定了id为mapRow的gaidiv进行扩展的-->
    </div>
</div>
{% endblock %}

{% block extrascripts %}
    <script type="text/javascript" src="/static/js/force/d3.js"></script>
    <script type="text/javascript" src="/static/js/force/d3.geom.js"></script>
    <script type="text/javascript" src="/static/js/force/d3.layout.js"></script>
    <script type="text/javascript" src="/static/weight/lib/d3.min.js" charset="utf-8"></script>
    <script type="text/javascript">
        var w = 1138,
        h = 942,
        node,
        link,
        root;

        var force = d3.layout.force()
        .on("tick", tick)//on:监听布局位置的变化。(仅支持"start","step","end"三种事件) tick让布局运行到下一步
        .charge(function(d) { return d._children ? -d.size / 100*3.5 : -30*3.5; })//获取或设置节点的电荷数.(电荷数决定结点是互相排斥还是吸引)
        .linkDistance(function(d) { return d.target._children ? 80*3 : 30*3; })//获取或设置节点间的连接强度.
        .size([w, h - 160]);// 获取或设置布局的 宽 和 高 的大小.

        var map=d3.select("#mapRow").append("svg").attr({id:"map",width:w,height:h});
        var vis=map.append("g");
        map.append("svg:defs").append("svg:marker").attr("id","arrow").attr("viewBox","0 -5 10 10").attr("refX",6).attr("markerWidth",5).attr("markerHeight",5).attr("orient","auto").append("svg:path").attr("d","M0,-5L10,0L0,5").attr("fill","#6ac6ff"),

        //$与jquery有关
        d3.json("/showtree/", function(json) {//读取JSON数据。并按照该数据进行绘图，即将这些数据可视化
        root = json;
        root.fixed = true;
        root.x = w / 2;//中心点坐标
        root.y = h / 2 ;
        update();
        });

        function update() {
        var nodes = flatten(root);//flatten以传入的参数root为根节点，进行迭代，将JSON数据解析，每项对应一个结点，并且为每一个节点赋予id
        var links = d3.layout.tree().links(nodes);//根据解析出来的结点，调用函数布置线

        // Restart the force layout.
        force
          .nodes(nodes)//获得或设置布局中的节点（node）阵列组
          .links(links)//获得或设置布局中节点间的连接（Link）阵列组
          .start();

        // Update the links…  vis之前定义了
        link = vis.selectAll("line.link")//这里相当于规定了line.link的样式，并不对应任何具体的元素或数据
          .data(links, function(d) { return d.target.id; });

        //reloadMap.js中为：s.selectAll("line.link").data(n).enter().append("line").attr("class","link");

        // Enter any new links. 然后再在这种样式下键入具体的元素 所谓"enter"
        link.enter().insert("svg:line", ".node")//.append("line")前期是准备数据 这里在插入如HTML元素 感叹一句 有了容器可以批量进行了
          .attr("class", "link")//insert 在当前元素之前插入
          .attr("x1", function(d) { return d.source.x; })//以下四项可以省略？在tick函数又执行了一遍
          .attr("y1", function(d) { return d.source.y; })
          .attr("x2", function(d) { return d.target.x; })
          .attr("y2", function(d) { return d.target.y; });


        // Exit any old links.
        link.exit().remove();//批量添加完所有line元素后，退出link（这个link是vis.selectAll("line.link")），并在退出之前清除多余的

        // Update the nodes…
        node = vis.selectAll("circle.node")
          .data(nodes, function(d) { return d.id; })
          .style("fill", color);

        // Enter any new nodes.
        node.enter().append("svg:circle")
          .attr("class", "node")
          .attr("cx", function(d) { return d.x; })//圆心
          .attr("cy", function(d) { return d.y; })
          .attr("r", function(d) { return d.children ? 12 : Math.sqrt(d.size)*8; }) //半径
          //.text(function(d) { return d.name; })
          .style("fill", color)//color和click是有名字的函数，具体函数体在下面写着，上面那些function(d)是匿名函数
          .call(force.drag)//force在之前定义过了 获取当前布局的拖拽对象实例以便进一步绑定处理函数.
          .on("click",click);//以上括号里面逗号前后都可以看成是后面对前面的赋值
          //.transition();
          //.attr("r", function(d) { return d.children ? 12 : Math.sqrt(d.size)*8; });

        // Exit any old nodes.
        node.exit().remove();
        }

        function tick() {//上边是赋值，还没有拉回来
        link.attr("x1", function(d) { return d.source.x; })
          .attr("y1", function(d) { return d.source.y; })
          .attr("x2", function(d) { return d.target.x; })
          .attr("y2", function(d) { return d.target.y; });

        node.attr("cx", function(d) { return d.x; })
          .attr("cy", function(d) { return d.y; });
        }

        // Color leaf nodes orange, and packages white or blue.
        function color(d) {
        if(d.depth){
        var c=["#1f77b4","#ff7f0e","#2ca02c","#d62728","#9467bd","#8c564b","#e377c2","#7f7f7f","#bcbd22","#17becf"];
        return c[d.depth];
        }else{
        return d._children ? "#3182bd" : d.children ? "#c6dbef" : "#fd8d3c";
        }

        }

        // Toggle children on click.
        function click(d) {
        if (d.children) {
        d._children = d.children;
        d.children = null;
        } else {
        d.children = d._children;
        d._children = null;
        }
        update();
        }

        // Returns a list of all nodes under the root.
        function flatten(root) {
        var nodes = [], i = 0;

        function recurse(node) {//这里只是定义了函数，但是未被调用，在后面才被调用  reduce回调函数
        if (node.children) for (x in node.children){recurse(node.children[x]);};//迭代，具体不深究了，总之沿一条路下去找到了叶子结点，突然发现这里的输入进来的数据格式真是我sparqltree的输入格式
        //if (node.children) node.size = node.children.reduce(function(p, v) { return p + recurse(v); }, 0);
        if (!node.id) node.id = ++i;
        nodes.push(node);//把node挤进nodes中 类似于append
        }

        recurse(root);//调用前面定义的函数，存入参数root，root才之前被赋予了JSON数据
        return nodes;
    }
    </script>
{% endblock %}
